package etc

import (
	"GateWay/api/internal/config"
	"context"
	clientv3 "go.etcd.io/etcd/client/v3"
	"log"
	"sync"
	"time"
)

var (
	lock         sync.RWMutex
	discoverDone = make(chan struct{}) // 服务发现完成通知通道
)

// DiscoverEtcdService 阻塞式服务发现（同步执行）
func DiscoverEtcdService(etcd *config.Etcd) {
	cli, err := clientv3.New(clientv3.Config{
		Endpoints:   []string{"localhost:2379"},
		DialTimeout: 5 * time.Second,
	})
	if err != nil {
		log.Fatal("ETCD连接失败:", err)
	}
	defer cli.Close()

	// 对应注册的服务名
	key := "/services/" + etcd.Name

	// 首次同步查询
	resp, err := cli.Get(context.Background(), key)
	if handleInitialDiscovery(resp, etcd) {
		return // 如果初次查询成功直接返回
	}

	// 启动异步监听
	go startServiceWatch(cli, key, etcd)

	// 阻塞等待直到发现服务地址
	select {
	case <-discoverDone: // 正常发现
		log.Printf("成功发现服务地址: %s", etcd.Addr)
	case <-time.After(30 * time.Second):
		log.Fatal("等待服务发现超时")
	}
}

// 处理初次服务发现
func handleInitialDiscovery(resp *clientv3.GetResponse, etcd *config.Etcd) bool {
	if len(resp.Kvs) > 0 {
		// 取第一个健康实例（实际生产环境应做健康检查）
		lock.Lock()
		etcd.Addr = string(resp.Kvs[0].Value)
		lock.Unlock()
		close(discoverDone)
		return true
	}
	log.Printf("服务 %s 未注册，启动监听...", etcd.Name)
	return false
}

// 启动服务监听
func startServiceWatch(cli *clientv3.Client, key string, etcd *config.Etcd) {
	watchChan := cli.Watch(context.TODO(), key)
	for watchResp := range watchChan {
		for _, event := range watchResp.Events {
			if processWatchEvent(event, etcd) {
				return // 成功获取地址后退出监听
			}
		}
	}
}

// 处理watch事件（返回是否完成发现）
func processWatchEvent(event *clientv3.Event, etcd *config.Etcd) bool {
	switch event.Type {
	case clientv3.EventTypePut:
		lock.Lock()
		defer lock.Unlock()

		// 只取第一个发现的地址（根据需求可改为列表）
		if etcd.Addr == "" {
			etcd.Addr = string(event.Kv.Value)
			log.Printf("监听到服务地址: %s", etcd.Addr)
			close(discoverDone) // 通知主流程继续执行
			return true
		}
	case clientv3.EventTypeDelete:
		// 生产环境需要处理节点下线逻辑
		log.Printf("服务实例下线: %s", string(event.Kv.Key))
	}
	return false
}
